/*
Script: Core.js
	MooTools - My Object Oriented JavaScript Tools.

License:
	MIT-style license.

Copyright:
	Copyright (c) 2006-2007 Valerio Proietti, <http://mad4milk.net/>

Code & Documentation:
	The MooTools production team <http://mootools.net/developers/>.

Inspiration:
	- Class implementation inspired by Base.js <http://dean.edwards.name/weblog/2006/03/base/> Copyright (c) 2006 Dean Edwards, GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
	- Some functionality inspired by Prototype.js <http://prototypejs.org> Copyright (c) 2005-2007 Sam Stephenson, MIT License <http://opensource.org/licenses/mit-license.php>
*/

var MooTools = {
	'version': '1.2dev',
	'build': '1.2b2'
};

//
//下面分析仅对于执行 new Native({name: String, initialize: String, protect: true});这个过程
//

var Native = function(options){
	options = options || {};

	var afterImplement = options.afterImplement || function(){}; //function(){}
	/*泛型(generic):指的是他们可以操作在多种容器类型上*/
	var generics = options.generics;
	generics = (generics !== false);//true
	var legacy = options.legacy; //undefined
	var initialize = options.initialize; //String - 构造函数
	var protect = options.protect; //true
	var name = options.name; //=String

	//构造函数-对象
	var object = initialize || legacy;
	
	//在执行下面之前 object.constructor = function Function(){[native code]} 这边的native跟Native不一样
	object.constructor = Native;
	//执行后,将Native（构造函数）赋给object.constructor

	/*静态的 myClass.$family.name -> class */
	object.$family = {name: 'native'};
	if (legacy && initialize) object.prototype = legacy.prototype;

	//注意,类型和对象,有Number类型也有Number对象;有Undefined类型但没有Undefined对象!有Null类型而无Null对象(呵,本来就表示没有何来对象.)
	if(typeof Native.__defined__ == 'undefined'){
		//alert(typeof object); //function
		//alert(object.prototype.constructor);
		Native.__defined__ = true;
	}
	/*
	 klass.prototype是klass类的原型对象,供“继承”klass的类使用.将klass本身赋予klass.prototype.constructor,可以使继承于klass的类具有klass的构造函数
	 对于大多数浏览器而言,这种操作是不需要的.constructor是Object的固有属性.但也有些浏览器没有将constructor作为Object的默认属性.所以就需要这样操作一下
	 所以.这种做法主要作用是可以跨浏览器
	 */
	//在执行下面代码之前 object.prototype.constructor = function String(){[native code]}
	object.prototype.constructor = object;

	if (name){
		var family = name.toLowerCase();
		object.prototype.$family = {name: family};
		Native.typize(object, family);
	}

	var add = function(obj, name, method, force){
		if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method;
		if (generics) Native.genericize(obj, name, protect);
		afterImplement.call(obj, name, method);
		return obj;
	};

	//静态方法,比如 String.implement({indexof:function(arg1,arg2){return this.indexOf(arg1,arg2)}});
	object.implement = function(a1, a2, a3){
		//String.implement('go',function(){});
		if (typeof a1 == 'string') return add(this, a1, a2, a3);
		//String.implement({fun1:function(){},fun2:function(){}});
		for (var p in a1) add(this, p, a1[p], a2);
		return this;
	};

	object.alias = function(existing, property, force){
		existing = this.prototype[existing];
		if (existing) add(this, property, existing, force);
		return this;
	};

	return object;
};

/*“静态方法”*/  /*附,常规方法:Object.prototype.implement = function(){}*/
//用于同时对多个对象进行扩展实现,子对象须被Native化,或者实现了名为implement的静态方法
Native.implement = function(objects, properties){
	for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties);
};
//方法静态化
//可以使用 String.push(obj,arg1,arg2,..);将arg1,arg2... push 到obj
Native.genericize = function(object, property, check){
	if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){
		//alert(arguments.length);
		var args = Array.prototype.slice.call(arguments);//把arguments'对象'转化成'数组'
		//alert(args instanceof Array);
		//Function.prototype.apply(thisArg,argArray)
		return object.prototype[property].apply(args.shift(), args);
		//把arguments分成: args.shift() - 被操作对象,args - 参数
	};
};
//使类支持类型比较,闭包使用技巧
Native.typize = function(object, family){
	if (!object.type) object.type = function(item){
		return ($type(item) === family);
	};
};

//内置对象:Global,Math
//宿主对象:所有BOM和DOM对象都是宿主对象

//本地对象:
//Object,Function,Array,String,Boolean,Number,Date,RegExp
//Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError
/*
因为js中的变量作用域只存在于function和with中,此处使用模块化写法避免全局变量污染,就地执行匿名方法
使Boolean/Native/Object支持类型比较操作 ?
*/
(function(objects){
	for (var name in objects) Native.typize(objects[name], name.toLowerCase());
})({'Boolean': Boolean, 'Native': Native, 'Object': Object});
/*
还是模块化写法
对下列内置类型进行Native化包装,使之支持类型化,拥有别名,继承等方法
*/
(function(objects){
	//其实new Native跟Native的结果应该是一样的，但是有时为了安全起见，用new能避免很多无法考虑的数据引用
	for (var name in objects) new Native({name: name, initialize: objects[name], protect: true});
})({'String': String, 'Function': Function, 'Number': Number, 'Array': Array, 'RegExp': RegExp, 'Date': Date});

//方法静态化 String.concat(mystring,'a string');
(function(object, methods){
	for (var i = 0, l = methods.length; i < l; i++) Native.genericize(object, methods[i], true);
	return arguments.callee;
})
(Array, ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice', 'toString', 'valueOf', 'indexOf', 'lastIndexOf'])
(String, ['charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'replace', 'search', 'slice', 'split', 'substr', 'substring', 'toLowerCase', 'toUpperCase', 'valueOf']);

function $chk(obj){
	return !!(obj || obj === 0);
};

function $clear(timer){
	clearTimeout(timer);
	clearInterval(timer);
	return null;
};

function $defined(obj){
	return (obj != undefined);
};

function $empty(){};

function $arguments(i){
	return function(){
		return arguments[i];
	};
};

function $lambda(value){
	return (typeof value == 'function') ? value : function(){
		return value;
	};
};

function $extend(original, extended){
	for (var key in (extended || {})) original[key] = extended[key];
	return original;
};

function $unlink(object){
	var unlinked = null;
	
	switch ($type(object)){
		case 'object':
			unlinked = {};
			for (var p in object) unlinked[p] = $unlink(object[p]);
		break;
		case 'array':
			unlinked = [];
			for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]);
		break;
		default: return object;
	}
	
	return unlinked;
};

function $merge(){
	var mix = {};
	for (var i = 0, l = arguments.length; i < l; i++){
		var object = arguments[i];
		if ($type(object) != 'object') continue;
		for (var key in object){
			var op = object[key], mp = mix[key];
			mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $merge(mp, op) : $unlink(op);
		}
	}
	return mix;
};

function $pick(){
	for (var i = 0, l = arguments.length; i < l; i++){
		if ($defined(arguments[i])) return arguments[i];
	}
	return null;
};

function $random(min, max){
	return Math.floor(Math.random() * (max - min + 1) + min);
};

function $splat(obj){
	var type = $type(obj);
	return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : [];
};

var $time = Date.now || function(){
	return new Date().getTime();
};

function $try(fn, bind, args){
	try {
		return fn.apply(bind, $splat(args));
	} catch(e){
		return false;
	}
};

function $type(obj){
	if (obj == undefined) return false;
	if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name;
	if (obj.nodeName){
		switch (obj.nodeType){
			case 1: return 'element';
			case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
		}
	} else if (typeof obj.length == 'number'){
		if (obj.callee) return 'arguments';
		else if (obj.item) return 'collection';
	}
	return typeof obj;
};

var Hash = new Native({

	name: 'Hash',

	initialize: function(object){
		if ($type(object) == 'hash') object = $unlink(object.getClean());
		for (var key in object){
			if (!this[key]) this[key] = object[key];
		}
		return this;
	}

});

Hash.implement({
	
	getLength: function(){
		var length = 0;
		for (var key in this){
			if (this.hasOwnProperty(key)) length++;
		}
		return length;
	},

	forEach: function(fn, bind){
		for (var key in this){
			if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this);
		}
	},
	
	getClean: function(){
		var clean = {};
		for (var key in this){
			if (this.hasOwnProperty(key)) clean[key] = this[key];
		}
		return clean;
	}

});

Hash.alias('forEach', 'each');

function $H(object){
	return new Hash(object);
};

Array.implement({

	//fuck ie,donot suppurts this function while ff yes. 2008-5-21 flashjay
	forEach: function(fn, bind){
		for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this);
	}

});

Array.alias('forEach', 'each');

function $A(iterable){
	if ($type(iterable) == 'collection'){
		var array = [];
		for (var i = 0, l = iterable.length; i < l; i++) array[i] = iterable[i];
		return array;
	}
	return Array.prototype.slice.call(iterable);
};

function $each(iterable, fn, bind){
	var type = $type(iterable);
	((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind);
};